package cate.game.role.task;

import cate.common.table.d.GDTask;
import cate.common.table.task.row.TaskLibRow;
import cate.game.event.task.TaskDoneEvent;
import cate.game.res.MixRes;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.task.msg.TaskGroupUpdateResp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.annotation.Transient;
import org.springframework.util.StringUtils;

import java.util.*;

@NoteClass("任务组数据")
public class TaskGroup extends RoleDependent {
    @NoteField(value = "该任务组对应的功能ID")
    public int funcId;

    @NoteField(value = "进行中的任务记录")
    public List<TaskItem> ingList;

    @NoteField(value = "已完成的任务记录")
    public List<TaskItem> doneList;

    /**
     * 已存在的任务ID
     */
    @JsonIgnore
    @Transient
    public Set<Integer> taskIdSet = new HashSet<>();

    public TaskGroup() {

    }

    public TaskGroup(Role role, int funcId) {
        super(role);
        this.funcId = funcId;
        initialize(role);
    }

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (ingList == null) {
            ingList = new ArrayList<>();
        }
        ingList.forEach(a -> a.initialize(role));
        if (doneList == null) {
            doneList = new ArrayList<>();
        }
        doneList.forEach(a -> a.initialize(role));
        ingList.removeIf(ing -> ing.getTpl() == null);
        doneList.removeIf(ing -> ing.getTpl() == null);
        ingList.forEach(
                item -> {
                    item.funcId = funcId;
                    taskIdSet.add(item.tid);
                });
        doneList.forEach(
                item -> {
                    item.funcId = funcId;
                    taskIdSet.add(item.tid);
                });
    }

    /**
     * 获取任务记录(可能返回null)
     */
    public synchronized TaskItem getItem(int taskId) {
        for (TaskItem item : ingList) {
            if (item.tid == taskId) {
                return item;
            }
        }
        for (TaskItem item : doneList) {
            if (item.tid == taskId) {
                return item;
            }
        }
        return null;
    }

    /**
     * 添加任务（同一个ID的任务不会被重复添加）
     */
    public synchronized TaskItem addItemNoRepeat(int taskId, boolean silence) {
        if (taskIdSet.contains(taskId)) {
            return null;
        }
        TaskLibRow tpl = role.getGame().table.task.lib.get(taskId);
        if (tpl == null) {
            logger.error("缺少id={}的任务！！！！", taskId);
            return null;
        }
        TaskItem item = new TaskItem(role, taskId, this.funcId);
        ingList.add(item);
        taskIdSet.add(taskId);
        if (!silence) {
            role.sendNow(new TaskGroupUpdateResp(item));
        }
        return item;
    }


    /**
     * 添加任务（同一个ID的任务不会被重复添加）
     */
    public List<TaskItem> addItemListNoRepeat(List<Integer> taskIds) {
        return addItemListNoRepeat(taskIds, false);
    }

    /**
     * 添加任务（同一个ID的任务不会被重复添加）
     */
    public synchronized List<TaskItem> addItemListNoRepeat(List<Integer> taskIds, boolean silence) {
        List<TaskItem> itemList = new ArrayList<>();
        for (Integer taskId : taskIds) {
            TaskItem item = addItemNoRepeat(taskId, true);
            if (item != null) {
                itemList.add(item);
            }
        }
        if (!silence && !CollectionUtils.isEmpty(itemList)) {
            role.sendNow(new TaskGroupUpdateResp(funcId, itemList));
        }
        return itemList;
    }

    /**
     * 删除任务
     */
    public synchronized void removeItemList(List<Integer> taskIds) {
        ingList.removeIf(task -> taskIds.contains(task.tid));
        doneList.removeIf(task -> taskIds.contains(task.tid));
        taskIdSet.removeIf(taskIds::contains);
    }

    public synchronized void removeAllItems() {
        ingList.clear();
        doneList.clear();
        taskIdSet.clear();
    }

    private boolean paramCorrect(TaskLibRow tpl, int param) {
        switch (tpl.checkParam) {
            case GDTask.CheckOper.EQ:
                return tpl.param == param;
            case GDTask.CheckOper.LTE:
                return tpl.param >= param;
            case GDTask.CheckOper.GTE:
                return tpl.param <= param;
            default:
                return false;
        }
    }

    /**
     * 记录历史值
     *
     * @param event 事件类型
     * @param param 参数
     * @param value 值
     * @param add   是否累加
     */
    public void record(int event, int param, long value, boolean add) {
        List<TaskItem> changes = new ArrayList<>();
        List<TaskItem> dones = new ArrayList<>();
        synchronized (this) {
            Iterator<TaskItem> iterator = ingList.iterator();
            while (iterator.hasNext()) {
                TaskItem item = iterator.next();
                if (item.getTpl() == null) {
                    iterator.remove();
                    continue;
                }
                if (event == item.getTpl().event && paramCorrect(item.getTpl(), param)) {
                    boolean change = item.setValue(value, add);
                    if (change) {
                        changes.add(item);
                    }
                }
                if (item.done) {
                    iterator.remove();
                    doneList.add(item);
                    dones.add(item);
                }
            }
        }
        for (TaskItem done : dones) {
            role.getGame().eventDispatcher.dispatchEvent(new TaskDoneEvent(role, done));
        }
        if (!changes.isEmpty() && role.getTask().initSend) {
            role.sendNow(new TaskGroupUpdateResp(funcId, changes));
        }
    }

    public synchronized void clear() {
        ingList.clear();
        doneList.clear();
        taskIdSet.clear();
    }

    public synchronized void addDoneListRewardInto(MixRes tar) {
        for (TaskItem task : this.doneList) {
            if (!task.rewardGot) {
                TaskLibRow tpl = task.getTpl();
                if (tpl != null && StringUtils.hasText(tpl.rewardStr)) {
                    tar.addList(new MixRes(tpl.rewardStr));
                }
            }
        }
    }

    public synchronized boolean isDoneEmpty() {
        return this.doneList == null || this.doneList.isEmpty();
    }

    @Override
    public void onDaySpan(boolean silence) {
        for (TaskItem item : ingList) {
            if (item.getTpl().duration == GDTask.Duration.DAILY) {
                item.reset();
                item.check();
            }
        }
    }

    @Override
    public void onWeekSpan(boolean  silence) {
        for (TaskItem item : ingList) {
            if (item.getTpl().duration == GDTask.Duration.WEEKLY) {
                item.reset();
                item.check();
            }
        }
    }
}
